'use strict';

// 1. 导入sequelize模块 和 DataTypes内置数据类型
// sequelize模块，相当于js代码与数据库之间的一个工具，通过这个工具将js代码映射成数据库中的表
// DataTypes内置数据类型，在模型（模型是 Sequelize 的本质. 模型是代表数据库中表的抽象）中定义的每一列都必须具有数据类型. Sequelize 提供很多内置数据类型. 要访问内置数据类型,必须导入 DataTypes
const { Sequelize, DataTypes } = require('sequelize');

// 2. 导入数据库配置文件
const { database, username, password, host, dialect } = require('./config');

// 3. 实例化 Sequelize 对象（四个参数，第一个为指定的数据库，第二个为登录数据库的账号，第三个为登录数据库的密码，第四个为一个对象，对象里为数据库服务器所在IP地址和所使用的数据库语言）
const sequelize = new Sequelize(database, username, password, {
    host: host,
    dialect: dialect
});

sequelize
    .authenticate()
    .then(() => {
        console.log('Connection has been established successfully');
    })
    .catch(err => {
        console.log('Unable to connect to the database:', err);
    });

// 4. 创建一个函数，包装模型的统一定义内容
function defineModel(tname, attrs) {
    // 所有的属性，预先定义好的属性和传进来指定的属性
    let prop = {};

    // 模型的id
    prop.id = {
        type: DataTypes.INTEGER, // int类型
        primaryKey: true, // 主键
        autoIncrement: true // 自增
    };

    // 循环遍历外部定义的模型传入的属性
    for (let item in attrs) {
        let value = attrs[item];
        prop[item] = value;
    };

    // 模型的创建时间
    prop.createAt = {
        type: DataTypes.BIGINT,
        allowNull: false // 不允许为空
    };

    // 模型的更新时间
    prop.updateAt = {
        type: DataTypes.BIGINT,
        allowNull: false // 不允许为空
    };

    // 备注
    prop.remarks = {
        type: DataTypes.STRING,
        allowNull: true // 允许为空
    };

    // 5. 利用sequelize实例定义模型（也就是数据库中的表）
    let obj = sequelize.define(tname, prop, {
        tableName: tname, // 强制表名称等于模型名称
        timestamps: false, // 不自动创建createAt 和 updateAt 时间戳
        // 钩子函数
        hooks: {
            // 生命周期钩子，也就是在插入或更新数据之前，会先触发这个钩子函数，给createAt和updateAt赋值
            beforeValidate: function (obj) {
                // 获取时间戳
                let now = Date.now();
                // 如果是要插入数据
                if (obj.isNewRecord) {
                    // 创建时间
                    obj.createAt = now;
                    // 更新时间
                    obj.updateAt = now;
                } else {
                    // 是更新数据
                    // 更新时间
                    obj.updateAt = now;
                }
            }
        }
    });
    return obj;
};

// 6. 创建一个对象,包含一个sequelize实例、定义模型的函数defineModel()、一个模型的内置数据类型DataTypes
let obj = {
    sequelize,
    defineModel,
    DataTypes
};

// 7. 暴露出去
module.exports = obj;

